using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Text;
using System.Linq;

namespace logPuzzle
{
    class PManagerBit: PManager
    {
        private PuzzlePiece[] m_PP = null;

        public PManagerBit(DataTable dtR, DataTable dtC, DataTable dtP)
            : base(dtR, dtC, dtP)
        {
            this.m_PP = new PuzzlePiece[this.m_dtC.Columns.Count * this.m_dtR.Rows.Count];
            for (int i = 0; i < this.m_PP.Length; i++)
            {
                this.m_PP[i] = new PuzzlePiece(this.m_PP, i);
            }

            for (int iC = 0; iC < this.m_dtC.Columns.Count; iC++)
            {
                this.m_dtP.Columns.Add(iC.ToString(), typeof(PuzzlePiece));
            }

            for (int iR = 0; iR < this.m_dtR.Rows.Count; iR++)
            {
                DataRow dr = this.m_dtP.NewRow();

                for (int iC = 0; iC < this.m_dtC.Columns.Count; iC++)
                {
                    int i = iR * this.m_dtC.Columns.Count + iC;
                    dr[iC.ToString()] = this.m_PP[i];
                }

                this.m_dtP.Rows.Add(dr);
            }
        }

        public override void Clear()
        {
            Array.ForEach<PuzzlePiece>(this.m_PP, delegate(PuzzlePiece pp)
            {
                pp.Clear();
            });
        }

        public override void Init()
        {
            for (int i = 0; i < this.m_dtR.Rows.Count; i++)
            {
                DataRow drr = this.m_dtR.Rows[i];
                DataRow drp = this.m_dtP.Rows[i];

                int ii = 0;

                foreach (object o in drr.ItemArray)
                {
                    if (o is DBNull) continue;

                    int j = (int)o;
                    for (int k = 0; k < j; k++)
                    {
                        PuzzlePiece pp = (PuzzlePiece)drp.ItemArray[ii++];
                        pp.B = true;
                    }
                    ii++;
                }
            }
        }

        private bool Convert2Bool(object o)
        {
            return o is DBNull ? false : ((PuzzlePiece)o).B;
        }

        private bool CheckData(object[] ob1, object[] ob2)
        {
            ob1 = Array.FindAll<object>(ob1, delegate(object o)
            {
                return !(o is DBNull);
            });
            int[] in1 = Array.ConvertAll<object, int>(ob1, Convert.ToInt32);


            bool[] bo2 = Array.ConvertAll<object, bool>(ob2, Convert2Bool);
            int i = 0;
            int[] in2 = new int[ob2.Length];
            Array.ForEach<bool>(bo2, delegate(bool b)
            {
                if (b) in2[i]++; else i++;
            });

            in2 = Array.FindAll<int>(in2, delegate(int j)
            {
                return j > 0;
            });

            return Enumerable.SequenceEqual<int>(in1, in2);
        }

        /*private object[] Convert2Obj(DataTable dt, int i)
        {
            return Array.ConvertAll<DataRow, object>(dt.Select(), delegate(DataRow row)
            {
                return row[i];
            });
        }*/

        private object[] Convert2Obj(DataRow[] drs, int i)
        {
            return Array.ConvertAll<DataRow, object>(drs, delegate(DataRow row)
            {
                return row[i];
            });
        }

        private bool CheckColumns(BackgroundWorker bW)
        {
            bool b = false;

            DataRow[] drc = this.m_dtC.Select();
            DataRow[] drp = this.m_dtP.Select();

            for (int i = 0; i < this.m_dtC.Columns.Count; i++)
            {
                object[] ob1 = Convert2Obj(drc, i);
                object[] ob2 = Convert2Obj(drp, i);

                b = CheckData(ob1, ob2);
                if (!b) return false;

                bW.ReportProgress(0);
            }

            return b;
        }

        private bool CheckRows(BackgroundWorker bW)
        {
            bool b = false;

            for (int i = 0; i < this.m_dtR.Columns.Count; i++)
            {
                DataRow drr = this.m_dtR.Rows[i];
                DataRow drp = this.m_dtP.Rows[i];

                b = CheckData(drr.ItemArray, drp.ItemArray);
                if (!b) return false;

                bW.ReportProgress(0);
            }

            return b;
        }

        public override void Generate(BackgroundWorker bW)
        {
            PuzzlePiece pc = this.m_PP[0];
            for (int i = 0; i < /*200; i++)*/System.Math.Pow(2, this.m_dtC.Columns.Count * this.m_dtR.Rows.Count); i++)
            {
                pc++;
                if (CheckRows(bW) && CheckColumns(bW)) return;
                //if (e.Cancel) return;
            }
        }

        class PuzzlePiece
        {
            private bool m_B = false;
            private PuzzlePiece[] m_PP = null;
            private int m_I;

            public PuzzlePiece(PuzzlePiece[] pp, int i)
            {
                this.m_PP = pp;
                this.m_I = i;
            }

            public bool B
            {
                get { return this.m_B; }
                set
                {
                    this.m_B = value;
                    if (!this.m_B)
                    {
                        PuzzlePiece pc = (PuzzlePiece)Next();
                        pc++;
                    };
                }
            }

            public object Next()
            {
                return this.m_PP[this.m_I + 1];
            }

            public override string ToString()
            {
                return m_B ? "X" : string.Empty;
            }

            public static PuzzlePiece operator ++(PuzzlePiece pc)
            {
                pc.B = !(pc.B && true);
                return pc;
            }

            public void Clear()
            {
                this.m_B = false;
            }
        }
    }
}
